-
Notifications
You must be signed in to change notification settings - Fork 160
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improved performance for group isomorphism/automorphisms #896
Conversation
Current coverage is 48.88% (diff: 47.29%)@@ master #896 diff @@
==========================================
Files 424 424
Lines 222125 222745 +620
Methods 3430 3430
Messages 0 0
Branches 0 0
==========================================
+ Hits 108344 108899 +555
- Misses 113781 113846 +65
Partials 0 0
|
064dba3
to
ce3ba7b
Compare
7cbe7ce
to
0bfda64
Compare
Thank you @hulpke! Could you please write a few words what this PR does ? Even if it's not needed to add an entry for the changes overview, some text which will help others to review the PR will be very useful. |
This is work in progress, I think, and as such does not (yet) need to be reviewed. Ultimately, it is what @hulpke wrote in the initial descritption. |
# space is fixed | ||
return G; | ||
fi; | ||
bas:=OnSubspacesByCanonicalBasis(bas,One(G)); # canonical form |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe replace this by the equivalent, but clearer (and slightly faster) TriangulizeMat(bas);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason I use OnSubspacesByCanonicalBasis
is because we don't promise that the canonical form is exactly the result of TriangulizeMat
(even though it currently is). As an action by OnSubspaces...
follows using it this way avoids issues, even if the definition of one of the two operations ever changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a matter of fact, we do promise that. To quote the documentation of OnSubspacesByCanonicalBasis
: "The function returns a mutable matrix which gives the basis of the image of the subspace in Hermite normal form. (In other words: it triangulizes the product of bas with mat.)"
|
||
one:=IdentityMat(n,field); | ||
sub:=[]; # space so far | ||
spaces:=Unique(List(spaces,x->OnSubspacesByCanonicalBasis(x,one))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace OnSubspacesByCanonicalBasis(x,one)
by TriangulizedMat(x)
Add(spaces,List(one,ShallowCopy)); | ||
fi; | ||
|
||
osporb:=List(osporb,x->List(x,x->OnSubspacesByCanonicalBasis(x,one))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace OnSubspacesByCanonicalBasis(x,one)
by TriangulizedMat(x)
.
s:=SumIntersectionMat(spaces[i],spaces[j]); | ||
for k in s do | ||
if Length(k)>0 and not ForAny(spaces,x->Length(x)=Length(k) and | ||
RankMat(Concatenation(x,k))=Length(x)) then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be better to insert TriangulizeMat(k);
before the if
, and then replace the RankMat
check by ... and x = k
. The speed should the same or sightly better (as the matrix is already close to HNF at this point, and only half as big as the concatenated matrix; and anyway, we don't have to create that new matrix). In addition, later on, when we handle new
, we have to triangulize its members anyway!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of course we should only triangulize if k is not empty. So full code might look like this (and since:
if Length(k) = 0 then continue; fi;
TriangulizeMat(k);
if not ForAny(spaces,x->Length(x)=Length(k) and x = k) then
and perhaps the if
could even be simplified to if not x in k
, though I am not sure how this would affect performance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lastly, I should mention that I run into a case where spaces
contains at least 48000 elements, so this part of the code is a major bottleneck... Unfortunately, its complexity is at least O(N^3), where N is the number of spaces. We could reduce this quite a lot by rewriting this code.
For starters, instead of keeping the single list spaces
, organize it in two levels: The first level is index by the dimension of the subspace, the second contains a set of spaces of the corresponding dimension.
This way, the second levels are sets, and GAP can peform a binary search. So the check would become
if not k in spaces[Length(k)] then
od; | ||
od; | ||
if Length(new)>0 then | ||
new:=List(new,x->OnSubspacesByCanonicalBasis(x,one)); # canonize |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace OnSubspacesByCanonicalBasis(x,one)
by TriangulizedMat(x)
. Or, since we replace new anyway, use a loop which uses TriangulizeMat
(no 'd', i.e. makes no copy). Or even better, make the modifications to the loop creating new
that I suggested above :-)
|
||
spaceincl:=function(big,small) | ||
return RankMat(Concatenation(big,small))=Length(big); | ||
end; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If big and small have equal length, then we don't need to invoke RankMat
. This can avoid quite some computational overhead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of course this becomes irrelevant if spaceincl
is removed, as I suggest below :-)
SortBy(spaces,Length); | ||
fi; | ||
until Length(new)=0; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Restarting like this can throw away a lot of perfectly fine information. In a bad case I have, we start out with about 4000 spaces, which is bad enough; but it then grows to NNN spaces, and starts over.
Why not instead have a workqueue: Initially, all spaces we in this workqueue, and spaces
is empty. Instead of iterating over spaces,
you iterate over the queue, and gradually add its entries to spaces
as well as their sum+intersection with all elements already in spaces
at that point. This way, you don't have to restart the loop.
The queue should perhaps also be grouped by dimensions (just as I suggested for spaces
, so that we can deal with 1-dimensional spaces first, if we want to, as those are easier to handle
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh, I just realized one issue with that: when adding a new space of dimension d
to spaces
, you'd have to either re-sort spaces[d]
(and that would invalidate incl
, unless you went through the trouble of applying the sort permutation there...). Or you don't sort it, but then you loose the fast check as to whether a space is already in there... Hrm.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(the NNN in my first comment should be 40000; though this is not the end, before I aborted the computation, new
already contained an additional 8000 unique spaces)
else | ||
# check for meet/join closed | ||
s:=SumIntersectionMat(spaces[i],spaces[j]); | ||
for k in s do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both SumIntersectionMat
and RankMat
(whcih is what spaceincl
calls) end up using SemiEchelonMatDestructive
. So we compute it twice in the worst case! Let's not do that :-). The easiest (albeit not most efficient, though hopefully it won't mattter) way woud be to always compute SumIntersectionMat
, and then check if s[2] = spaces[i]
.
258378d
to
fc44a2c
Compare
98a0ef8
to
07ebece
Compare
Now I get this warning:
|
@fingolfin: Harmless warning which is fixed now in 7eae649 |
Another error I run into (should be easy to fix):
|
Conflicts: lib/autsr.gi
Ensure generating sets remain consistent. Fixed variable name in copied code bit Conflicts: lib/autsr.gi
Utilize a given `autactbase' to help with pc group automorphisms.
… numbers. Instead of abelian invariants use factors of index of G'.
Also ensure that automorphism group is automorphismgroup and fix comment. Two small fixes in ordering if there is trivial orbit on lines
Allow degree up to 100000 (computers are bigger now) before hard Use maximal subgroups in trying perm rep. (Do not use maxsub in factor if called from maxsub) FIX: another recursion avoidance.
There are two different situations in which PcSeries is called. The first is a good pcgs and we happen to want the series -- this is the existing code. The second case is that the series is needed to do anything with the pcgs. In this case inducing caused bad recursions. Avoid this.
In some situations, it seems that ClosurePermGroup can iterate very long time with evrification failing repeatedly. In this situation we now simply force a new stabilizer chain computation from scratch, than trying to bend the (apparently confused) chain in the right way. This is not a beautiful fix but a workaround, albeit one that should have litlle cost implications.
ENHANCE: Declare `SpaceAndOrbitStabilizer'
…roup. Relax threshold for new permrep force. FIX: Change reading order to avoid forward declaration Also ensure a maximal subgroups computation for smaller permutation degree stays out of expensive operations.
@hulpke thanks - testing is currently underway (seems there will be diffs - repot will follow). Is there any text that you're suggesting for the overview of changes in GAP 4.9? |
@alex-konovalov |
@hulpke thanks - I've copied it to the 1st comment above, to make it easily seen. |
@hulpke first, if you run
|
@hulpke second, the manual examples test with default packages has diffs below. They look ok to me (I have checked that groups in
and
|
@hulpke finally, I haven't seen |
@hulpke for the record, the If there is a way to give more lightweight tests, these heavy tests may go into the |
I've tried to run
though it takes about an hour to get there. Just suggested to use |
@alex-konovalov |
This happens only with |
The message "Alternating recognition needed" is triggered also in #763 without packages for the example A5 x A5. So this seems to make a problem for consistent tests between with and without packages. |
Ongoing improvements for automorphism group/group isomorphism:
Use
PatheticIsomorphism
also for pc groups.Permit specifying characteristic subgroups in pc group automorphism case. Try to do so without computing long orbits.
Improvements to permutation representation of automorphism group.
Added by @alex-konovalov: this PR is described in the commit message in 9e38dd1:
Further enhancements to group automorphisms
This PR contains a number of improvements and additions for testing of group isomorphism, respectively calculation of automorphism groups. It has been tested over several months and is merged to avoid too much divergence between master and development branches.
The main effect of this change should be a significantly improved performance for group isomorphism/automorphisms.
The main changes are: